/*****************************************************************************
 *   Copyright (C) 2008 John Schember <john@nachtimwald.com>                 *
 *                                                                           *
 *   This file is part of niwbillmanager.                                    *
 *                                                                           *
 *   niwbillmanager is free software: you can redistribute it and/or         *
 *   modify it under the terms of the GNU General Public License as          *
 *   published by the Free Software Foundation, either version 3 of the      *
 *   License, or (at your option) any later version.                         *
 *                                                                           *
 *   niwbillmanager is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
 *   GNU General Public License for more details.                            *
 *                                                                           *
 *   You should have received a copy of the GNU General Public License       *
 *   along with niwbillmanager. If not, see                                  *
 *   <http://www.gnu.org/licenses/>.                                         *
 *****************************************************************************/

#include "backendmanager.h"

#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QFileInfoList>
#include <QPluginLoader>

#include "../constants.h"

BackendManager::BackendManager()
{
    m_backend = 0;

    loadStaticBackends();
    findDynamicBackends();
}

BackendManager::~BackendManager()
{
    m_backend = 0;

    Q_FOREACH (BackendInterface *backend, m_staticBackends) {
        delete backend;
    }
    m_staticBackends.clear();
}

QStringList BackendManager::getAvaliableBackends()
{
    QStringList backends;

    Q_FOREACH (QString backend, m_avaliableBackends.uniqueKeys()) {
        backends << backend;
    }

    return backends;
}

BackendInterface* BackendManager::getCurrentBackend()
{
    if (m_backend) {
        return m_backend;
    }

    return 0;
}

bool BackendManager::setCurrentBackend(QString name)
{
    if (isBackend(name)) {
        if (getCurrentBackend()) {
            if (!isBackendStatic(getCurrentBackend()->getName())) {
                delete m_backend;
            }
        }

        if (isBackendStatic(name)) {
            m_backend = m_staticBackends.value(name);
            return true;
        }
        else {
            QPluginLoader pluginLoader(m_avaliableBackends.value(name));

            if (pluginLoader.load()) {
                m_backend = qobject_cast<BackendInterface *>(pluginLoader.
                    instance());
                return true;
            }
        }
    }

    return false;
}

QString BackendManager::getBackendDescription(QString name)
{
    if (isBackend(name)) {
        if (isBackendStatic(name)) {
            return m_staticBackends.value(name)->getDescription();
        }
        else {
            QPluginLoader pluginLoader(m_avaliableBackends.value(name));

            if (pluginLoader.load()) {
                return qobject_cast<BackendInterface *>(pluginLoader.
                    instance())->getDescription();
                pluginLoader.unload();
            }
        }
    }

    return QString();
}

bool BackendManager::isBackendRemote(QString name)
{
    if (isBackend(name)) {
        if (isBackendStatic(name)) {
            return m_staticBackends.value(name)->isRemote();
        }
        else {
            QPluginLoader pluginLoader(m_avaliableBackends.value(name));

            if (pluginLoader.load()) {
                return qobject_cast<BackendInterface *>(pluginLoader.
                    instance())->isRemote();
                pluginLoader.unload();
            }
        }
    }

    return false;
}

bool BackendManager::isBackend(QString name)
{
    if (m_avaliableBackends.contains(name)) {
        return true;
    }

    return false;
}

bool BackendManager::isBackendStatic(QString name)
{
    if (m_avaliableBackends.value(name) == "static") {
        return true;
    }
    else {
        return false;
    }
}

void BackendManager::loadStaticBackends()
{
    BackendInterface *backendPlugin;

    // Test code for loading statically compiled plugins
    Q_FOREACH(QObject *plugin, QPluginLoader::staticInstances()) {
        backendPlugin = qobject_cast<BackendInterface *>(plugin);
        if (backendPlugin) {
            if (!m_avaliableBackends.contains(backendPlugin->getName())) {
                m_staticBackends.insert(backendPlugin->getName(),
                    backendPlugin);
                m_avaliableBackends.insert(backendPlugin->getName(), "static");
                setCurrentBackend(backendPlugin->getName());
            }
        }
    }
}

void BackendManager::findDynamicBackends()
{
    QStringList BackendPaths;
    BackendPaths << Constants::BackendPath
        << QCoreApplication::applicationDirPath() + "/backends";

    QDir dir;
    dir.setFilter(QDir::Readable | QDir::Files | QDir::NoDotAndDotDot);
    dir.setSorting(QDir::Name);

    QPluginLoader pluginLoader;

    Q_FOREACH (QString path, BackendPaths) {
        if (QFile::exists(path)) {
            dir.setPath(path);

            QFileInfoList list = dir.entryInfoList();
            Q_FOREACH (QFileInfo file, list) {
                pluginLoader.setFileName(file.absoluteFilePath());
                if (pluginLoader.load()) {
                    BackendInterface *backendPlugin;

                    backendPlugin = qobject_cast<BackendInterface *>
                        (pluginLoader.instance());
                    if (backendPlugin) {
                        m_avaliableBackends.insert(backendPlugin->getName(),
                            file.absoluteFilePath());
                    }
                    pluginLoader.unload();
                }
            }
        }
    }
}
